﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FA.Plugins.FSXPlugin.Sim;
using System.Threading;
using System.Windows.Forms;
using FA.Library.Plugin;
using FA.Library.Sim.Events;
using FA.Library.ExtensionMethods;
using FA.Library.Sim;
using FA.Library.Sim.Aircraft;

namespace FA.Plugins.FSXPlugin.Plugin
{
    public class FSXPlugin : IPlugin
    {
        public const string SETTING_NAME_HOST = "host";
        public const string SETTING_NAME_PORT = "port";

        public event EventHandler Disposed;
        public event EventHandler OnPluginStartEvent;
        public event EventHandler OnPluginStopEvent;
        public event EventHandler OnPluginSettingsChangedEvent;
        public event SimMessageEvent OnSimMessageEvent;
        public event SimExceptionEvent OnSimExceptionEvent;
        public event SimAircraftModelChangedEvent OnSimAircraftModelChangedEvent;
        
        public string Name { get; set; }

        public AircraftModel AircraftModel
        {
            get
            {
                AircraftModel model = null;
                if (_simController != null && _simController.AircraftModel != null)
                {
                    model = (AircraftModel)_simController.AircraftModel.Clone();
                }
                return model;
            }
        }

        public bool IsRunning
        {
            get { return _isRunning; }
            private set
            {
                if (_isRunning != value)
                {
                    _isRunning = value;

                    if (_isRunning && OnPluginStartEvent != null)
                        OnPluginStartEvent(this, null);
                    else if (!_isRunning && OnPluginStopEvent != null)
                        OnPluginStopEvent(this, null);
                }
            }
        }
        private bool _isRunning = false;

        public bool IsDisposed { get; private set; }

        private Dictionary<string, string> _settings = new Dictionary<string, string>();
        private SimController _simController;

        /// <summary>
        /// Initialise the plugin.
        /// </summary>
        /// <param name="host"></param>
        public void Initialise()
        {
            if (String.IsNullOrEmpty(Name))
                Name = "Unnamed";
        }

        /// <summary>
        /// Dispose the plugin.
        /// </summary>
        public void Dispose()
        {
            if (IsDisposed)
                return;

            if (_simController != null)
            {
                _simController.Dispose();
                _simController = null;
            }

            IsRunning = false;
            IsDisposed = true;

            if (Disposed != null)
                Disposed(this, null);
        }

        /// <summary>
        /// Run the plugin.
        /// </summary>
        public void Start()
        {
            // Get the settings
            string host = getSetting(SETTING_NAME_HOST);
            int port = int.Parse(getSetting(SETTING_NAME_PORT));

            // Create the sim controller
            _simController = new SimController(Name, host, port);
            _simController.Connected += new Action(simController_Connected);
            _simController.Disposed += new Action(simController_Disposed);
            _simController.AircraftModelUpdated += new Action(simController_AircraftModelUpdated);

            // Create a new controller
            _simController.Run();
        }

        /// <summary>
        /// Stop the plugin.
        /// </summary>
        public void Stop()
        {
            // Dispose the controller
            _simController.Dispose();
            _simController = null;
        }

        /// <summary>
        /// Update the settings.
        /// </summary>
        /// <param name="settings"></param>
        public void UpdateSettings(Dictionary<string, string> settings)
        {
            if (settings == null)
                settings = new Dictionary<string, string>();

            if (!_settings.CheckForEquality<string, string>(settings))
            {
                _settings = settings;

                if (OnPluginSettingsChangedEvent != null)
                    OnPluginSettingsChangedEvent(this, null);
            }
        }

        /// <summary>
        /// Get the settings.
        /// </summary>
        /// <returns></returns>
        public Dictionary<string, string> GetSettings()
        {
            // Return a cloned copy
            return _settings.ToDictionary(entry => entry.Key, entry => entry.Value);
        }

        /// <summary>
        /// Update the aircraft model for the plugin.
        /// </summary>
        /// <param name="model"></param>
        public void UpdateAircraftModel(AircraftModel model, bool supressEvent)
        {
            _simController.UpdateAircraftModel(model, supressEvent);
        }

        public override string ToString()
        {
            return Name;
        }

        /// <summary>
        /// Get the setting value. Returns NULL if the setting doesn't exist.
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        private string getSetting(string name)
        {
            string value;

            if (_settings.TryGetValue(name, out value))
                return value;
            else
                throw new Exception("Could not locate setting '" + name + "'.");
        }

        #region SimController event handling

        private void simController_Connected()
        {
            IsRunning = true;
        }

        private void simController_Disposed()
        {
            IsRunning = false;
        }

        private void simController_AircraftModelUpdated()
        {
            if (OnSimAircraftModelChangedEvent != null)
                OnSimAircraftModelChangedEvent(this, new SimAircraftModelChangedEventArgs(AircraftModel));
        }

        #endregion
    }
}
